package com.wang.springframework.context.event;

import com.wang.springframework.beans.BeansException;
import com.wang.springframework.beans.factory.BeanFactory;
import com.wang.springframework.beans.factory.BeanFactoryAware;
import com.wang.springframework.context.ApplicationEvent;
import com.wang.springframework.context.ApplicationListener;
import com.wang.springframework.util.ClassUtils;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.Set;

/**
 * @author wangjianhua
 * @Description
 * @date 2021/8/30/030 21:55
 */
public abstract class AbstractApplicationEventMulticaster implements ApplicationEventMulticaster, BeanFactoryAware {

    private final Set<ApplicationListener<ApplicationEvent>> applicationListeners = new LinkedHashSet<>();

    private BeanFactory beanFactory;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    @SuppressWarnings("unchecked")
    @Override
    public void addApplicationListener(ApplicationListener<?> listener) {
        applicationListeners.add((ApplicationListener<ApplicationEvent>)listener);
    }

    @Override
    public void removeApplicationListener(ApplicationListener<?> listener) {
        applicationListeners.remove(listener);
    }

    protected Collection<ApplicationListener> getApplicationListeners(ApplicationEvent event){
        LinkedList<ApplicationListener> allListeners = new LinkedList<>();
        for (ApplicationListener<ApplicationEvent> listener : applicationListeners) {
            if (supportsEvent(listener,event))
            {
                //如果感兴趣 则加入
              allListeners.add(listener);
            }
        }
        return allListeners;
    }

    /**
     * 监听器是否对该事件感兴趣
     * @param applicationListener applicationListener
     * @param event 事件
     * @return boolean
     */
    protected boolean supportsEvent(ApplicationListener<ApplicationEvent> applicationListener,ApplicationEvent event){

        Class<? extends ApplicationListener> listenerClass = applicationListener.getClass();
        //按照CglibSubclassingInstantiationStrategy、SimpleInstantiationStrategy 不同的实例化类型，需要判断后获取目标 class
        Class<?> targetClass = ClassUtils.isCglibProxyClass(listenerClass)? listenerClass.getSuperclass() : listenerClass;
        Type genericInterface = targetClass.getGenericInterfaces()[0];

        Type actualTypeArgument = ((ParameterizedType)genericInterface).getActualTypeArguments()[0];
        String className = actualTypeArgument.getTypeName();
        Class<?> eventClassName;

        try
        {
            eventClassName = Class.forName(className);
        }
        catch (ClassNotFoundException e)
        {
            throw new BeansException("wrong event class name:"+className);
        }
        //判定此EventClassName 对象所展示的类或接口与指定的 event.getClass() 参数所表示的类或接口是否相同 或是否为其超类 或超接口
        //isAssignableFrom 是用来判断子类和父类的关系的 或者接口的实现类与接口的关系的 默认所有的类的父类为Object
        // 如果A.isAssignableFrom(B)为true 证明B可以转换为A 也就是A可以由B转换而来

        return eventClassName.isAssignableFrom(event.getClass());
    }
}
